from django.shortcuts import render
from alipay import AliPay
from django.conf import settings
# Create your views here.
from rest_framework.response import Response
from rest_framework.views import APIView
from orders.models import Order
from rest_framework.permissions import IsAuthenticated
from rest_framework import status
from django.db import transaction
from datetime import datetime
from users.models import UserCourse
from django.http import HttpResponse

def get_alipay():
    """获取支付宝处理对象"""
    app_private_key_string = open(settings.ALIAPY_CONFIG["app_private_key_path"]).read()
    alipay_public_key_string = open(settings.ALIAPY_CONFIG["alipay_public_key_path"]).read()

    alipay = AliPay(
        appid=settings.ALIAPY_CONFIG["appid"],
        app_notify_url=settings.ALIAPY_CONFIG["app_notify_url"],  # 默认回调url
        app_private_key_string=app_private_key_string,
        # 支付宝的公钥，验证支付宝回传消息使用，不是你自己的公钥,
        alipay_public_key_string=alipay_public_key_string,
        sign_type="RSA2",  # RSA2
        debug=True  # 默认False
    )

    return alipay

class AlipayAPIView(APIView):
    permission_classes = [IsAuthenticated]
    def get(self,request,order_number):
        """生成支付宝的支付链接"""
        try:
            order = Order.objects.get(order_number=order_number)
        except:
            return Response("订单不存在！")

        alipay = get_alipay()

        # 电脑网站支付，需要跳转到https://openapi.alipay.com/gateway.do? + order_string
        order_string = alipay.api_alipay_trade_page_pay(
            out_trade_no=order_number,                # 订单号
            total_amount=float(order.real_price),     # 订单价格[元]
            subject=order.order_title,                # 订单标题
            return_url=settings.ALIAPY_CONFIG["return_url"],
            notify_url=settings.ALIAPY_CONFIG["notify_url"]
        )

        # 拼接链接地址
        gateway_url = settings.ALIAPY_CONFIG["gateway_url"] + order_string

        return Response(gateway_url)

class AlipayResultAPIView(APIView):
    """支付宝的支付结果处理"""

    def orderhandler(self,data):
        """订单处理"""
        # 支付成功！
        # 获取支付成功的结果中的订单号
        order_number = data.get("out_trade_no")
        try:
            order = Order.objects.get(order_number=order_number)
            if order.order_status != 0:
                return Response({"message": "订单已过期或者重复支付！"},
                            status=status.HTTP_400_BAD_REQUEST)
        except Order.DoesNotExist:
            return Response({"message": "对不起，支付结果查询失败！请联系客服工作人员"},
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        with transaction.atomic():
            """开启事务来完成订单相关信息的修改"""
            # 事务回滚点
            save_id = transaction.savepoint()
            try:
                # 修改订单状态和订单支付时间
                order.pay_time = datetime.now()
                order.order_status = 1  # 1表示已支付
                order.save()

                # 补充积分流水[自己补充]  1,用户，操作类型，数值

                # 记录用户成功购买课程的记录, 增加课程的购买人数
                order_detail_list = order.order_courses.all()

                # 拼接返回给客户端的购买课程列表
                course_list = []

                for order_detail in order_detail_list:
                    """循环本次订单中所有购买的商品课程"""
                    course = order_detail.course
                    course.students += 1
                    course.save()

                    # 把用户和课程的购买信息记录下来
                    try:
                        user = order.user
                        # 查询之前有没有购买记录
                        user_course = UserCourse.objects.get(course=course, user_id=user.id)
                        # 之前购买过同一个课程
                        if user_course.out_time.timestamp() > datetime.now().timestamp():
                            """之前购买的课程没有过期，更新当前记录的过期时间[过期时间+本次购买的课程有效期]"""
                            """判断本次购买课程是购买一段时间还是永久购买"""
                            if order_detail.expire > 0:
                                """有效期购买"""
                                # 计算新的过期时间戳
                                out_time = user_course.out_time.timestamp() + order_detail.expire * 24 * 60 * 60
                                # 把时间戳转换成日期时间对象
                                user_course.out_time = datetime.fromtimestamp(out_time)

                            else:
                                """永久  购买"""
                                user_course.out_time = "2199-01-01 00:00:00"
                        else:
                            """之前购买的课程已经过期，更新当前记录的过期时间[当前时间+本次购买的课程有效期]"""
                            if order_detail.expire > 0:
                                """有效期购买"""
                                out_time = datetime.now().timestamp() + order_detail.expire * 24 * 60 * 60
                                user_course.out_time = datetime.fromtimestamp(out_time)
                            else:
                                """永久  购买"""
                                user_course.out_time = "2199-01-01 00:00:00"

                        user_course.trade_no = data.get("trade_no")
                        user_course.save()

                    except UserCourse.DoesNotExist:
                        """之前没有过同一个课程，则新增记录"""
                        if order_detail.expire > 0:
                            """有效期购买"""
                            out_time = datetime.now().timestamp() + order_detail.expire * 24 * 60 * 60
                            out_time = datetime.fromtimestamp(out_time)
                        else:
                            """永久  购买"""
                            out_time = "2199-01-01 00:00:00"

                        UserCourse.objects.create(
                            user=user,
                            course=course,
                            trade_no=data.get("trade_no"),
                            buy_type=1,
                            pay_time=datetime.now(),
                            out_time=out_time
                        )

                    course_list.append({"course_name": course.name, "course_id": course.id})
                order.course_list = course_list
                return order

            except:
                transaction.savepoint_rollback(save_id)
                return Response({"message": "对不起，支付结果处理失败！请联系客服工作人员"},
                                status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def get(self,request):
        """同步通知结果处理"""
        data = request.query_params.dict()
        signature = data.pop("sign")
        alipay = get_alipay()

        success = alipay.verify(data, signature)
        if success:

            result = self.orderhandler(data)
            if isinstance(result, Order):
                # 处理订单正常
                ret = {
                    "message":"支付成功！",
                    "pay_time": result.pay_time,
                    "order_price": result.real_price,
                    "course_list": result.course_list,
                }
                return Response(ret)
            else:
                # 处理订单有误
                return result

        return Response({"message":"支付失败！支付结果有误！"})

    def post(self,request):
        """支付结果的异步通知
        1. 支付宝访问不了本地局域网，
        2. 异步通知采用post请求在25小时内分8次访问当前地址，程序执行完后必须打印输出“success”（不包含引号）。如果商户反馈给支付宝的字符不是 success 这7个字符，支付宝服务器会不断重发通知，直到超过24小时22分钟。一般情况下，25小时以内完成8次通知（通知的间隔频率一般是：4m,10m,10m,1h,2h,6h,15h）；
        """
        data = request.data.dict()
        signature = data.pop("sign")
        alipay = get_alipay()

        success = alipay.verify(data, signature)
        if success and data["trade_status"] in ("TRADE_SUCCESS", "TRADE_FINISHED" ):

            result = self.orderhandler(data)
            if isinstance(result, Order):
                # 处理订单正常
                ret = {
                    "message":"支付成功！",
                    "pay_time": result.pay_time,
                    "order_price": result.real_price,
                    "course_list": result.course_list,
                }
                return Response(ret)
            else:
                # 处理订单有误
                return result

        return HttpResponse("success")